﻿//Copyright 2014 Thomas Rega

//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at

//http://www.apache.org/licenses/LICENSE-2.0

//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.

using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;

namespace TinyDeduplicator
{
    class DeduplicationFile
    {
        private const string ZEROBYTEFILEHASH = "00000000000000000000000000000000";

        private static MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();

        private FileInfo file;
        private byte[] hash;

        internal DeduplicationFile(FileInfo file)
        {
            this.file = file;
        }

        //kludgey hack. Only calculate hash in the equals method, as it is an expensive operation,
        //and the length-check in the hashcode should weed out most duplication candidates. -trega
        public override bool Equals(object obj)
        {
            bool equals = false;

            if ((object)obj != null)
            {
                DeduplicationFile other = (DeduplicationFile)obj;

                if (file.Length == other.file.Length)
                {
                    if (file.Length == 0)
                    {
                        equals = true;
                    }
                    else
                    {
                        if ((object)hash == null)
                        {
                            hash = md5.ComputeHash(file.OpenRead());
                        }

                        if ((object)other.hash == null)
                        {
                            other.hash = md5.ComputeHash(other.file.OpenRead());
                        }

                        equals = hash.SequenceEqual(other.hash);
                    }
                }
            }

            return equals;
        }

        //kludgey hack. This is cheap; however, it will yield potential hash collisions when
        //dealing with files larger than 4GB. -trega
        public override int GetHashCode()
        {
            return file.Length.GetHashCode();
        }

        internal FileInfo fileInfo
        {
            get
            {
                return file;
            }
        }

        internal string md5Hash
        {
            get
            {
                string hashString;

                if ((object)hash == null)
                {
                    hashString = ZEROBYTEFILEHASH;
                }
                else
                {
                    hashString = BitConverter.ToString(hash).Replace("-", string.Empty);
                }

                return hashString;
            }
        }
    }
}
